package net.protocol.diameter.message;

import net.protocol.common.coding.ByteMe;
import net.protocol.diameter.avp.AVP;

import java.util.Collection;

/**
 * <h3>Protocol description</h3>
 * <p/>
 * <p/>
 * The Diameter base protocol is defined by RFC 6733, and defines the minimum
 * requirements for an AAA protocol. Diameter Applications can extend the base
 * protocol, by adding new commands and/or attributes. Diameter security is
 * provided by IPSEC or TLS, both well-regarded protocols. The IANA has assigned
 * TCP and SCTP port number 3868 to Diameter.
 * <p/>
 * <h4>Packet format</h4>
 * <p/>
 * <p/>
 * The packet consists of a Diameter header and a variable number of
 * Attribute-Value Pairs, or AVPs, for encapsulating information relevant to the
 * Diameter message.
 * <p/>
 * <pre>
 *     0                   1                   2                   3
 *     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *    |    Version    |                 Message Length                |
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *    | command flags |                  Command-Code                 |
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *    |                         Application-ID                        |
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *    |                      Hop-by-Hop Identifier                    |
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *    |                      End-to-End Identifier                    |
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *    |  AVPs ...
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-
 *
 * Version
 *       This Version field MUST be set to 1 to indicate Diameter Version
 *       1.
 *
 * Message Length
 *       The Message Length field is three octets and indicates the length
 *       of the Diameter message including the header fields.
 *
 * Command Flags
 *       The Command Flags field is eight bits.  The following bits are
 *       assigned:
 *
 *        0 1 2 3 4 5 6 7
 *       +-+-+-+-+-+-+-+-+
 *       |R P E T r r r r|
 *       +-+-+-+-+-+-+-+-+
 *
 *       R(equest)   - If set, the message is a request.  If cleared, the
 *                     message is an answer.
 *       P(roxiable) - If set, the message MAY be proxied, relayed or
 *                     redirected.  If cleared, the message MUST be
 *                     locally processed.
 *       E(rror)     - If set, the message contains a protocol error,
 *                     and the message will not conform to the ABNF
 *                     described for this command.
 *       T(Potentially re-transmitted message)
 *                   - This flag is set after a link failover procedure,
 *                     to aid the removal of duplicate requests.
 *
 *       r(eserved)  - these flag bits are reserved for future use, and
 *                     MUST be set to zero, and ignored by the receiver.
 *    Command-Code
 *       The Command-Code field is three octets, and is used in order to
 *       communicate the command associated with the message.  The 24-bit
 *       address space is managed by IANA (see Section 11.2.1).
 *
 *       Command-Code values 16,777,214 and 16,777,215 (hexadecimal values
 *       FFFFFE -FFFFFF) are reserved for experimental use (See Section
 *       11.3).
 *
 *    Application-ID
 *       Application-ID is four octets and is used to identify to which
 *       application the message is applicable for.
 *
 *       The application-id in the header MUST be the same as what is
 *       contained in any relevant AVPs contained in the message.
 *
 *    Hop-by-Hop Identifier
 *       The Hop-by-Hop Identifier is an unsigned 32-bit integer field (in
 *       network byte order) and aids in matching requests and replies.
 *
 *    End-to-End Identifier
 *       The End-to-End Identifier is an unsigned 32-bit integer field (in
 *       network byte order) and is used to detect duplicate messages.
 *
 *   AVPs
 *       AVPs are a method of encapsulating information relevant to the
 *       Diameter message.
 * </pre>
 * <p/>
 * <h4>AVP Header</h4>
 * <p/>
 * <pre>
 *     The fields in the AVP header MUST be sent in network byte order.  The
 *     format of the header is:
 *
 *      0                   1                   2                   3
 *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *     |                           AVP Code                            |
 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *     |V M P r r r r r|                  AVP Length                   |
 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *     |                        Vendor-ID (opt)                        |
 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *     |    Data ...
 *     +-+-+-+-+-+-+-+-+
 * </pre>
 *
 * @author jinhongw@gmail.com
 * @see <a href="http://tools.ietf.org/html/rfc6733#page-34">Diameter Base Protocol - Diameter Header</a>
 * @see <a href="http://en.wikipedia.org/wiki/Diameter_%28protocol%29">Diameter (protocol)</a>
 */
public interface DiameterMessage extends Iterable<AVP<?>>, ByteMe {

    /**
     * Returns the type[request | answer] of the Diameter Message.
     *
     * @return true if the message is a request
     */
    boolean isRequest();

    /**
     * Returns the type[proxy | local] of the Diameter Message.
     *
     * @return true if the message is a proxiable
     */
    boolean isProxiable();

    /**
     * Returns the type[error | normal] of the Diameter Message.
     *
     * @return true if the message is a error
     */
    boolean isError();

    /**
     * Returns the type of the Diameter Message.
     *
     * @return true if the message is a re-transmitted
     */
    boolean isReTransmitted();

    /**
     * If set, the message MAY be proxied, relayed or redirected. If cleared,
     * the message MUST be locally processed.
     *
     * @param value whether to set message is a proxiable
     */
    void setProxiable(boolean value);

    /**
     * If set, the message contains a protocol error.This bit MUST NOT be set in
     * request messages.
     *
     * @param value whether to set message is a error
     */
    void setError(boolean value);

    /**
     * This flag is set after a link failover procedure, to aid the removal of
     * duplicate requests.
     *
     * @param value whether to set message is a re-transmitted
     */
    void setReTransmitted(boolean value);

    /**
     * @return Version This Version field MUST be set to 1 to indicate Diameter
     *         Version 1.
     */
    byte getVersion();

    /**
     * @return The Message Length field is three octets and indicates the length
     *         of the Diameter message including the header fields.
     */
    int getMessageLength();

    /**
     * @param messageLength Diameter message length
     */
    void setMessageLength(int messageLength);

    /**
     * @return The Command Flags field is eight bits.
     */
    byte getCommandFlags();

    /**
     * @return The Command-Code field is three octets, and is used in order to
     *         communicate the command associated with the message.
     */
    int getCommandCode();

    /**
     * @return Application-ID is four octets and is used to identify to which
     *         application the message is applicable for.
     */
    int getApplicationID();

    /**
     * @param applicationID Application-ID
     */
    void setApplicationID(int applicationID);

    /**
     * The Hop-by-Hop Identifier is an unsigned 32-bit integer
     * 
     * @return The Hop-by-Hop Identifier is an unsigned 32-bit integer field (in
     *         network byte order) and aids in matching requests and replies.
     */
    long getHopByHopIdentifier();

    /**
     * @param hopByHopIdentifier The Hop-by-Hop Identifier is an unsigned 32-bit integer
     */
    void setHopByHopIdentifier(long hopByHopIdentifier);

    /**
     * The End-to-End Identifier is an unsigned 32-bit integer
     * 
     * @return The End-to-End Identifier is an unsigned 32-bit integer field (in
     *         network byte order) and is used to detect duplicate messages.
     */
    long getEndToEndIdentifier();

    /**
     * @param endToEndIdentifier The End-to-End Identifier is an unsigned 32-bit integer
     */
    void setEndToEndIdentifier(long endToEndIdentifier);
    
	/**
	 * Appends the specified element[<code>AVP</code>] to the end of this
	 * <code>DiameterMessage</code>.
	 * 
	 * @param avp
	 *            <code>AVP</code> element to be appended to this
	 *            <code>DiameterMessage</code>
	 * @return <tt>true</tt> (as specified by {@link Collection#add})
	 */
    boolean add(AVP<?> avp);

    /**
     * @param avps collection containing elements[<code>AVP</code>] to be added to this
     * <code>DiameterMessage</code>.
     *
     * @return <tt>true</tt> if this <code>DiameterMessage</code> changed as a result of the call
     */
    boolean addAll(Collection<AVP<?>> avps);
    
	/**
	 * Returns the number of <code>AVP</code> in this <code>DiameterMessage</code>.
	 * 
	 * @return the number of <code>AVP</code> in this <code>DiameterMessage</code>
	 */
	int size();

	/**
	 * Returns <tt>true</tt> if this <code>DiameterMessage</code> contains no <code>AVP</code>.
	 * 
	 * @return <tt>true</tt> if this <code>DiameterMessage</code> contains no <code>AVP</code>.
	 */
	boolean isEmpty();
}
